package com.mm.scheme.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mm.common.config.RedisProperties;
import com.mm.common.domain.po.Result;
import com.mm.common.enums.ResultCode;
import com.mm.common.utils.cacheUtil.CacheClient;
import com.mm.common.utils.DataUtils;
import com.mm.common.utils.SessionHolder;
import com.mm.scheme.config.AiUtils;
import com.mm.scheme.config.SchemeProperties;
import com.mm.scheme.domian.dto.SchemeListDTO;
import com.mm.scheme.domian.po.Scheme;
import com.mm.scheme.domian.po.Step;
import com.mm.scheme.domian.po.Template;
import com.mm.scheme.exception.AiException;
import com.mm.scheme.mapper.SchemeMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @BelongsProject: chatgpt-java-develop
 * @BelongsPackage: com.unfbx.service
 * @Author : 游在海里的鱼
 * @CreateTime : 2024-03-20  20:13
 * @Version : 1.0
 * @ClassName : TODO
 * @Description : TODO
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SchemeServiceImpl extends ServiceImpl<SchemeMapper,Scheme> implements ISchemeService {

    private final CacheClient cacheClient;
    private final AiUtils aiUtils;
    private final SchemeProperties schemeProperties;
    private final RedisProperties redisProperties;
    private final TemplateServiceImpl templateService;

    /** ---------------------------------------------------------------------------------------------------------------------
     * @Method  : 新增方案
     **/
    public Result addScheme(){

        int count = lambdaQuery().eq(Scheme::getUid, SessionHolder.getUser()).count();
        if(count >= schemeProperties.scheme_capacity){
            return Result.failed(ResultCode.FAILED_OVER_CAPACITY);
        }

        //检验是否有“未命名方案”没有处理
        Scheme scheme = lambdaQuery().eq(Scheme::getTitle,schemeProperties.default_scheme_title)
                .eq(Scheme::getUid, SessionHolder.getUser()).one();
        if(scheme != null){
            return Result.failed(ResultCode.FAILED_TITLE_DUPLICATIO);
        }
        //初始化模板
        scheme = new Scheme();
        scheme.setUid(SessionHolder.getUser());
        scheme.setTitle(schemeProperties.default_scheme_title);
        initialize(scheme);
        //保存模板
        if(!save(scheme)){
            return Result.failed(ResultCode.FAILED);
        }
        //获取模板在数据库里的模板
        Scheme cur = lambdaQuery().eq(Scheme::getTitle,schemeProperties.default_scheme_title)
                .eq(Scheme::getUid, SessionHolder.getUser()).one();
        if(cur == null){
            return Result.failed(ResultCode.FAILED);
        }
        //清空缓存
        String key = redisProperties.cache_scheme_list_pre + SessionHolder.getUser();
        cacheClient.removeCache(key);
        //返回方案id
        return Result.success(cur.getId());
    }
    
    /** ---------------------------------------------------------------------------------------------------------------------
     * @Method  : 编辑方案
     * @Describe: TODO
     * @modifier: [public] [实例方法]
     **/
    public Result editScheme(Scheme scheme){
        //参数检验
        if(scheme == null
                || DataUtils.isNaturalNumInvalid(scheme.getId())
                || StrUtil.isBlank(scheme.getTitle()) 
                || StrUtil.isBlank(scheme.getSteps())){
            return Result.failed(ResultCode.FAILED_PARAMS_VALIDATE);
        }

        //检验此ID的方案是否存在
        Scheme cur = getById(scheme.getId());
        if(cur == null){
            return Result.failed(ResultCode.FAILED);
        }

        //判断方案标题是否重复
        Scheme cur2 = lambdaQuery().eq(Scheme::getTitle,scheme.getTitle())
                .eq(Scheme::getUid, SessionHolder.getUser())
                .one();
        if(cur2 != null && cur2.getId() != cur.getId()){
            return Result.failed(ResultCode.FAILED_TITLE_DUPLICATIO);
        }

        //修改并保存
        cur.setAll(scheme);
        cur.setUpdateTime(new Date());
        if(!saveOrUpdate(scheme)){
            log.error("[addScheme] [方案:"+scheme.getTitle()+"]修改失败");
            return Result.failed(ResultCode.FAILED);
        }

        //清缓存
        String key1 = redisProperties.cache_scheme_list_pre + SessionHolder.getUser();
        String key2 = redisProperties.cache_scheme_pre + cur.getId();
        cacheClient.removeCache(key1);
        cacheClient.removeCache(key2);

        //成功
        return Result.success();
    }

    /** ---------------------------------------------------------------------------------------------------------------------
     * @Method  : 删除方案
     * @Describe: TODO
     * @modifier: [public] [实例方法]
     **/
    public Result deleteScheme(Long id){
        //参数检验
        if(DataUtils.isNaturalNumInvalid(id)){
            return Result.failed(ResultCode.FAILED_PARAMS_VALIDATE);
        }
        //检验uid是否匹配
        Scheme scheme = getById(id);
        if(scheme == null){
            log.error("[deleteScheme] [ID:" +id+"]的方案不存在");
            return Result.failed(ResultCode.FAILED);
        }
        //删除方案
        if(!removeById(id)){
            return Result.failed(ResultCode.FAILED);
        }
        //清空模板缓存
        String key1 = redisProperties.cache_scheme_list_pre + SessionHolder.getUser();
        String key2 = redisProperties.cache_scheme_pre + id;
        cacheClient.removeCache(key1);
        cacheClient.removeCache(key2);
        //成功
        return Result.success();
    }

    /** ---------------------------------------------------------------------------------------------------------------------
     * @Method  : 获取此用户的所有方案
     * @Describe: TODO
     * @modifier: [public] [实例方法]
     **/
    public Result getAllScheme(){
        //获取方案列表
        List<SchemeListDTO> schemeList = cacheClient.queryListPassThrough(redisProperties.cache_scheme_list_pre, SessionHolder.getUser(), SchemeListDTO.class
                , redisProperties.cache_scheme_time, TimeUnit.MINUTES,this::selectSchemeAll);

        if(schemeList == null){
            log.error("[getAllScheme] [用户："+ SessionHolder.getUser()+"]获取所有方案失败");
            return Result.failed(ResultCode.FAILED);
        }
        log.info("[getAllScheme] [用户："+ SessionHolder.getUser()+"]获取所有成功");
        return Result.success(schemeList);
    }

    /* ---------------------------------------------------------------------------------------------------------------------
     * @Method  : 查询所有方案
     **/
    private List<SchemeListDTO> selectSchemeAll(Long uid){
        List<Scheme> schemeList = lambdaQuery().eq(Scheme::getUid,uid).orderByDesc(Scheme::getUpdateTime).list();
        return BeanUtil.copyToList(schemeList,SchemeListDTO.class);
    }


    /** ---------------------------------------------------------------------------------------------------------------------
     * @Method  : 获取此用户的方案
     * @Describe: TODO
     * @modifier: [public] [实例方法]
     **/
    public Result getScheme(Long schemeId){
        if(DataUtils.isNaturalNumInvalid(schemeId)){
            return Result.failed(ResultCode.FAILED_PARAMS_VALIDATE);
        }
        //获取方案
        Scheme scheme = cacheClient.queryPassThrough(redisProperties.cache_scheme_pre,schemeId,Scheme.class,
                redisProperties.cache_scheme_time,TimeUnit.MINUTES,this::getById);
        if(scheme == null){
            log.error("[getScheme] 获取[方案"+schemeId+"]失败");
            return Result.failed(ResultCode.FAILED);
        }
        log.info("[getScheme] 获取[方案"+schemeId+"]成功");
        return Result.success(scheme);
    }

    /** ---------------------------------------------------------------------------------------------------------------------
     * @Method  : 获取方案的输入参数
     * @Describe: TODO
     * @modifier: [public] [实例方法]
     **/
    public Result getInput(Long schemeId){
        //参数检验
        if(DataUtils.isNaturalNumInvalid(schemeId)){
            return Result.failed(ResultCode.FAILED_PARAMS_VALIDATE);
        }
        //获取方案
        Scheme scheme = cacheClient.queryPassThrough(redisProperties.cache_scheme_pre,schemeId,Scheme.class,
                redisProperties.cache_scheme_time,TimeUnit.MINUTES,this::getById);
        if(scheme == null){
            log.error("[getScheme] 获取[方案"+schemeId+"]失败");
            return Result.failed(ResultCode.FAILED);
        }
        return Result.success(scheme.getInput());
    }

    /** ---------------------------------------------------------------------------------------------------------------------
     * @Method  : 使用方案
     * @Describe: TODO
     * @modifier: [public] [实例方法]
     **/
    public Result useScheme(String map, Long schemeId){
        //获取方案
        Scheme scheme = cacheClient.queryPassThrough(redisProperties.cache_scheme_pre,schemeId,Scheme.class,
                redisProperties.cache_scheme_time,TimeUnit.MINUTES,this::getById);
        if(scheme == null){
            log.error("[getInput] [ID:" +schemeId+"]的方案不存在");
            return Result.failed(ResultCode.FAILED);
        }

        //获取inputMap
        Map<String,String> inputMap = JSONUtil.toBean(map,HashMap.class);
        //获取templateMap
        List<Template> templateList = cacheClient.queryListPassThrough(redisProperties.cache_template_list_pre, SessionHolder.getUser(), Template.class
                , redisProperties.cache_template_time, TimeUnit.MINUTES,templateService::selectTemplateAll);;
        //定义paramMap，并添加inputMap的键值对
        Map<String,Object> paramMap = new HashMap<>();
        paramMap.putAll(inputMap);

        //添加templateMap
        for(Template template:templateList){
            paramMap.put(template.getTitle(),template.getContent());
        }

        //4.解析Scheme为steps
        Queue<Step> steps = resolveStep(scheme,paramMap);
        if(steps == null){
            log.error("[useScheme] 将[方案:"+scheme.getTitle()+"]的stepsJSON转成Step对象失败");
            return Result.failed(ResultCode.ERROR_SERVICES);
        }

        List<String> resultList = new ArrayList<>();
        //4.执行steps
        int count = 0;
        Step step = null;
        try {
            while (steps.size()>0){
                count++;
                step = steps.poll();
                if(step.getFunc() <6 && step.getFunc()!=2){
                    resultList.add((String) paramMap.get(step.function()));
                }else if(step.getFunc() == 8){
                    Queue<String[]> queueStrs = (Queue<String[]>) paramMap.get(step.function());
                    StringBuilder builder2 =new StringBuilder();
                    for(String[] strs:queueStrs){
                        for(String str2: strs){
                            builder2.append(str2);
                            builder2.append("\n");
                        }
                        builder2.append("------------\n\n");
                    }
                    resultList.add(builder2.toString());
                }else {
                    Queue<String> queue = (Queue<String>) paramMap.get(step.function());
                    StringBuilder builder1 =new StringBuilder();
                    for(String str1: queue){
                        builder1.append(str1);
                        builder1.append("\n");
                    }
                    resultList.add(builder1.toString());
                }

            }
        } catch (AiException e){
            resultList.add("当前AI使用过载,请稍后再试");
            return Result.success(resultList);
        }
        catch (Exception e) {
            e.printStackTrace();
            resultList.add("[步骤: "+count+"]出错\n"+step.toString());
            return Result.success(resultList);
        }
        return Result.success(resultList);
    }


    /* ---------------------------------------------------------------------------------------------------------------------
     * @Method  : 解析前端的Steps为Step队列
     * @Describe: TODO
     * @modifier: [private] [实例方法]
     **/
    private Queue<Step> resolveStep(Scheme scheme, Map<String,Object> paramMap){
        Queue<Step> ret = new LinkedList<>();
        List<Step> stepList = JSONUtil.toList(scheme.getSteps(),Step.class);
        for(Step step:stepList){
            step.setAiUtils(aiUtils);
            step.setParamMap(paramMap);
        }

        ret.addAll(stepList);
        return ret;
    }

    

    /* ---------------------------------------------------------------------------------------------------------------------
     * @Method  : 初始化方案
     * @Describe: TODO
     * @modifier: [private] [实例方法]
    **/
    private boolean initialize(Scheme scheme){
        if(scheme.getTitle() == null  ){
            scheme.setTitle("未命名方案");
        }
        if(scheme.getSteps() == null){
            scheme.setSteps(schemeProperties.default_scheme_steps);
        }
        if(scheme.getInput() == null){
            scheme.setInput(schemeProperties.default_scheme_input);
        }
        if(scheme.getCreateTime() == null){
            scheme.setCreateTime(new Date());
        }
        if(scheme.getUpdateTime() == null){
            scheme.setUpdateTime(new Date());
        }
        return true;
    }
}
